﻿// ----------------------------------------------------------------------------------------
// Author:                    Magaly Vargas y Joaquín López
// Company:                   ALBALIA INTERACTIVA S.L.
// Assembly version:          1.0.0.0
// Date:                      22/02/2010
// Time:                      12:00
// Solution Name:             OffInvoiceWordAddIn
// Solution Filename:         OffInvoiceWordAddIn
// Solution FullFilename:     C:\Desarrollo\OffInvoiceWordAddIn
// Project Name:              OffInvoiceWordAddIn
// Project Filename:          OffInvoiceWordAddIn.csproj
// Project FullFilename:      C:\Desarrollo\OffInvoiceWordAddIn\OffInvoiceWordAddIn.csproj
// Project Item Name:         FacturaeGenerator.cs
// Project Item Filename:     FacturaeGenerator.cs
// Project Item FullFilename: C:\Desarrollo\OffInvoiceWordAddIn\FacturaeFiles\FacturaeGenerator.cs
// Project Item Kind:         Código
// Purpose:                   
//Copyright © 2009 - 2010 Albalia Interactiva S.L. Reservados todos los derechos.
// ----------------------------------------------------------------------------------------



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Interop.Word;
using System.Windows.Forms;
using System.Globalization;
using System.Reflection;
using System.Xml.Serialization;
using OffInvoiceWordAddIn.FacturaeFiles;
using OffInvoiceWordAddIn.UBLFiles;

namespace OffInvoiceWordAddIn.FacturaeFiles
{
    /// <summary>
    /// Clase encargada de formar la facturae de acuerdo con los datos insertados en la plantilla
    /// completa la informacion y realiza los calculos y operaciones necesarias para formar la facturae
    /// </summary>
    /// <remarks>
    /// algunos datos son opcionales por lo que dependen de ciertos valores que aparezcan en el xml.
    /// los campos nulos no aprecen en el documento
    /// </remarks>
    class FacturaeGenerator
    {
        #region Fields

        /// <summary>
        /// Estructura de Facturae sobre la cual se realizan las operaciones y cálculos para completar la factura
        /// </summary>
        Facturae facturae;

        /// <summary>
        /// Constituye el bloque de datos del tercero, se utiliza cuando el emisor de la factura es una tercera parte
        /// </summary>
        ThirdPartyType thirdParty;

        /// <summary>
        /// documento de plantilla de facturae, en el que se completan los datos de la factura
        /// </summary>
        Document document;

        /// <summary>
        /// Constituye el bloque Batch de la facturae, especifica el identificador del lote de la factura así como los totales de las facturas
        /// </summary>
        BatchType batch;

        /// <summary>
        /// Constituye el bloque de datos del Emisor de la factura
        /// </summary>
        BusinessType sellerParty;

        /// <summary>
        /// Constituye el bloque de datos del receptor ó cliente de la factura
        /// </summary>
        BusinessType buyerParty;

        /// <summary>
        /// Constituye la estructura de la factura
        /// </summary>
        InvoiceType invoice;

        /// <summary>
        /// Constituye el bloque de datos del encabezado de la factura
        /// </summary>
        InvoiceHeaderType invoiceHeader;

        /// <summary>
        /// Constituye el bloque de datos de emision de la factura
        /// </summary>
        InvoiceIssueDataType invoiceIssueData;

        /// <summary>
        /// Array de caracteres que se deben remover de los valores tomados directamente de las celdas de una tabla
        /// <example>
        /// <code>
        /// string descripcion = document.Tables[t2].Rows[i].Cells[2].Range.Text.Trim(x).Trim();
        /// </code>
        /// </example>
        /// </summary>
        char[] x = { '\r', '\a', '\n' };

        /// <summary>
        /// almacena el índice de la tabla de detalles
        /// </summary>
        int t2;

        /// <summary>
        /// almacena el índice de la tabla de descuentos
        /// </summary>
        int t3;

        /// <summary>
        /// almacena el índice de la tabla de observaciones
        /// </summary>
        int t4;

        /// <summary>
        /// almacena el índice de la tabla de totales
        /// </summary>
        int t5;

        /// <summary>
        /// almacena el indice de la tabla de informacion de tercero
        /// </summary>
        int t6;

        double GeneralDiscountBase;

        /// <summary>
        /// totalGrossAmount = el monto total bruto antes de los descuentos generales
        /// </summary>

        double totalGrossAmount;


        /// <summary>
        /// totalGeneralDiscount = total de los descuentos generales
        /// </summary>
        double totalGeneralDiscounts;

        /// <summary>
        ///  TotalTaxesOutputs = total de impuestos repercutidos
        /// </summary>
        double TotalTaxesOutputs;


        /// <summary>
        /// TotalTaxesWithHeld = total de impuestos retenidos
        /// </summary>
        double TotalTaxesWithHeld;

        /// <summary>
        /// almacena la cultura instalda con el SO para realizar cálculos
        /// </summary>
        CultureInfo culturaFactura;

        /// <summary>
        /// especifica la cultura inglesa que es el formato que tiene el formato de facturae
        /// </summary>
        CultureInfo culturaOffice;

        /// <summary>
        /// Especifica si la factura a generar es electrónoca o de papel(convencional)
        /// </summary>
        bool paperInvoice = false;

        string control = "";

        int facturaeVersion = 0;

        Calculos calculos;

        FacturaeFieldAndValues datos;

        double exchangeRate;

        CurrencyCodeType moneda;

        #endregion

        #region Constructors

        /// <summary>
        /// Construye un objeto de tipo Facturae
        /// </summary>
        /// <param name="facturae">instancia de la clase facturae que se estructura para formar la Factura</param>
        /// <param name="document">documento basado en una plantilla de facturae de la que se tomaran los datos para completar la factura</param>
        /// <param name="InvoiceCulture">Referencia cultoral que se utilizo al momento de completar los datos de la plantilla</param>
        /// <param name="PaperInvoice">Indica si la factura a generar será de papel (convencional)</param>
        public FacturaeGenerator(Facturae facturae, Document document, bool PaperInvoice, int facturaeVersion, Calculos calculos, FacturaeFieldAndValues datos)
        {
            try
            {

                this.facturaeVersion = facturaeVersion;

                this.facturae = facturae;
                this.document = document;
                this.calculos = calculos;

                this.datos = datos;

                culturaOffice = new CultureInfo(Globals.ThisAddIn.Application.LanguageSettings.get_LanguageID(Microsoft.Office.Core.MsoAppLanguageID.msoLanguageIDUI));

                culturaFactura = new CultureInfo("en-US");

                this.paperInvoice = PaperInvoice;

                enumerateTables();

                try
                {
                    exchangeRate = double.Parse(Globals.ThisAddIn.GetControlValue(ControlList.Tag.ExchangeRate),culturaOffice.NumberFormat);
                }
                catch (Exception)
                {
                    
                    throw;
                }
                

                facturae.FileHeader.InvoiceIssuerType = convertToInvoiceIssuerType(this.datos.getValueByFieldName("InvoiceIssuerType"));

                if (facturaeVersion.Equals(InvoceTypes.FACTURAE_3_1))
                {
                    facturae.FileHeader.SchemaVersion = SchemaVersionType.Item31;
                }
                else if (facturaeVersion.Equals(InvoceTypes.FACTURAE_3_2))
                {
                    facturae.FileHeader.SchemaVersion = SchemaVersionType.Item32;
                }

                moneda = convertToCurrencyType(this.datos.getValueByFieldName("InvIssue_InvoiceCurrencyCode"));

                facturae.FileHeader.ThirdParty = getThirdParty();
                facturae.Parties.SellerParty = getSellerParty();
                facturae.Parties.BuyerParty = getBuyerParty();
                facturae.Invoices.Add(getInvoice());
                facturae.FileHeader.Batch = getBatch();

            }
            catch (Exception e)
            {

                throw e;
            }

        }


        #endregion

        #region Informacion


        /// <summary>
        /// Se encarga de formar el bloque de datos del tercero en caso del que el emisor de la factura sea una tercera entidad
        /// </summary>
        /// <returns>La estructura de datos del tercero, completa con los datos tomados de la plantilla</returns>
        private ThirdPartyType getThirdParty()
        {
            ControlMessages msg = ControlMessages.getInstance();

            thirdParty = null;

            if (facturae.FileHeader.InvoiceIssuerType.Equals(InvoiceIssuerTypeType.TE))
            {
                thirdParty = new ThirdPartyType();

                string persontype = this.datos.getValueByFieldName("TH_PersonTypeCode");
                string residentType = this.datos.getValueByFieldName("TH_ResidenceTypeCode");
                string taxIdentificationNumber = this.datos.getValueByFieldName("TH_TaxIdentificationNumber");

                if (string.IsNullOrEmpty(persontype))
                {
                    Globals.ThisAddIn.getControlByTag(ControlList.Tag.TH_PersonTypeCode).Range.Select();
                    throw new Exception(msg.getMessage("MsgIncompleteData"));
                }
                thirdParty.TaxIdentification.PersonTypeCode = convertToPersonType(this.datos.getValueByFieldName("TH_PersonTypeCode"));


                if (string.IsNullOrEmpty(residentType))
                {
                    Globals.ThisAddIn.getControlByTag(ControlList.Tag.TH_ResidenceTypeCode).Range.Select();
                    throw new Exception(msg.getMessage("MsgIncompleteData"));
                }
                thirdParty.TaxIdentification.ResidenceTypeCode = convertToResidenceType(this.datos.getValueByFieldName("TH_ResidenceTypeCode"));

                if (string.IsNullOrEmpty(taxIdentificationNumber))
                {
                    Globals.ThisAddIn.getControlByTag(ControlList.Tag.TH_TaxIdentificationNumber).Range.Select();
                    throw new Exception(msg.getMessage("MsgIncompleteData"));
                }
                else
                {
                    string country3 = this.datos.getValueByFieldName("TH_CountryCode");
                    if (InvoiceValidations.validarCif(taxIdentificationNumber, country3))
                    {
                        if (taxIdentificationNumber.Length == 9)
                        {
                            string country2 = InvoiceValidations.ConvertToString(InvoiceValidations.convertToCountryType(country3));
                            taxIdentificationNumber = string.Concat(country2, taxIdentificationNumber);
                        }
                    }
                    else
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.TH_TaxIdentificationNumber).Range.Select();
                        throw new Exception(msg.getMessage("ErrorInvalidCIFTH"));
                    }
                }
                thirdParty.TaxIdentification.TaxIdentificationNumber = taxIdentificationNumber;

                thirdParty.Item = getTypePerson(Parent.ThirdParty, thirdParty.TaxIdentification);
            }

            return thirdParty;
        }


        /// <summary>
        /// Se encarga de formar el bloque de datos correspondiente a la parte que emite la factura 
        /// </summary>
        /// <returns>La estructura completa con los datos del emisor tomados de la plantilla</returns>
        private BusinessType getSellerParty()
        {
            ControlMessages msg = ControlMessages.getInstance();

            sellerParty = new BusinessType();

            string persontype = this.datos.getValueByFieldName("SP_PersonTypeCode");
            string residentType = this.datos.getValueByFieldName("SP_ResidenceTypeCode");
            string taxIdentificationNumber = this.datos.getValueByFieldName("SP_TaxIdentificationNumber");

            if (string.IsNullOrEmpty(persontype))
            {
                Globals.ThisAddIn.getControlByTag(ControlList.Tag.SP_PersonTypeCode).Range.Select();
                throw new Exception(msg.getMessage("MsgIncompleteData"));
            }
            sellerParty.TaxIdentification.PersonTypeCode = convertToPersonType(this.datos.getValueByFieldName("SP_PersonTypeCode"));

            if (string.IsNullOrEmpty(residentType))
            {
                Globals.ThisAddIn.getControlByTag(ControlList.Tag.SP_ResidenceTypeCode).Range.Select();
                throw new Exception(msg.getMessage("MsgIncompleteData"));
            }
            sellerParty.TaxIdentification.ResidenceTypeCode = convertToResidenceType(this.datos.getValueByFieldName("SP_ResidenceTypeCode"));


            if (string.IsNullOrEmpty(taxIdentificationNumber))
            {
                Globals.ThisAddIn.getControlByTag(ControlList.Tag.SP_TaxIdentificationNumber).Range.Select();
                throw new Exception(msg.getMessage("MsgIncompleteData"));
            }
            else
            {
                string country3 = this.datos.getValueByFieldName("SP_CountryCode");
                if (InvoiceValidations.validarCif(taxIdentificationNumber, country3))
                {
                    if (taxIdentificationNumber.Length == 9)
                    {
                        string country2 = InvoiceValidations.ConvertToString(InvoiceValidations.convertToCountryType(country3));
                        taxIdentificationNumber = string.Concat(country2, taxIdentificationNumber);
                    }
                }
                else
                {
                    Globals.ThisAddIn.getControlByTag(ControlList.Tag.SP_TaxIdentificationNumber).Range.Select();
                    throw new Exception(msg.getMessage("ErrorInvalidCIFSP"));
                }
            }
            sellerParty.TaxIdentification.TaxIdentificationNumber = taxIdentificationNumber;


            sellerParty.Item = getTypePerson(Parent.SellerParty, sellerParty.TaxIdentification);

            return sellerParty;
        }

        /// <summary>
        /// Se encarga de formar el bloque de datos correspondiente a la parte que recibe la factura 
        /// </summary>
        /// <returns>La estructura completa con los datos del Cliente tomados de la plantilla</returns>
        private BusinessType getBuyerParty()
        {
            buyerParty = new BusinessType();
            ControlMessages msg = ControlMessages.getInstance();

            string persontype = this.datos.getValueByFieldName("BP_PersonTypeCode");
            string residentType = this.datos.getValueByFieldName("BP_ResidenceTypeCode");
            string taxIdentificationNumber = this.datos.getValueByFieldName("BP_TaxIdentificationNumber");

            if (string.IsNullOrEmpty(persontype))
            {
                Globals.ThisAddIn.getControlByTag(ControlList.Tag.BP_PersonTypeCode).Range.Select();
                throw new Exception(msg.getMessage("MsgIncompleteData"));
            }
            buyerParty.TaxIdentification.PersonTypeCode = convertToPersonType(this.datos.getValueByFieldName("BP_PersonTypeCode"));


            if (string.IsNullOrEmpty(residentType))
            {
                Globals.ThisAddIn.getControlByTag(ControlList.Tag.BP_ResidenceTypeCode).Range.Select();
                throw new Exception(msg.getMessage("MsgIncompleteData"));
            }
            buyerParty.TaxIdentification.ResidenceTypeCode = convertToResidenceType(this.datos.getValueByFieldName("BP_ResidenceTypeCode"));


            if (string.IsNullOrEmpty(taxIdentificationNumber))
            {
                Globals.ThisAddIn.getControlByTag(ControlList.Tag.BP_TaxIdentificationNumber).Range.Select();
                throw new Exception(msg.getMessage("MsgIncompleteData"));
            }
            else
            {
                string country3 = this.datos.getValueByFieldName("BP_CountryCode");
                if (InvoiceValidations.validarCif(taxIdentificationNumber, country3))
                {
                    if (taxIdentificationNumber.Length == 9)
                    {
                        string country2 = InvoiceValidations.ConvertToString(InvoiceValidations.convertToCountryType(country3));
                        taxIdentificationNumber = string.Concat(country2, taxIdentificationNumber);
                    }
                }
                else
                {
                    Globals.ThisAddIn.getControlByTag(ControlList.Tag.BP_TaxIdentificationNumber).Range.Select();
                    throw new Exception(msg.getMessage("ErrorInvalidCIFBP"));
                }
            }
            buyerParty.TaxIdentification.TaxIdentificationNumber = taxIdentificationNumber;

            buyerParty.Item = getTypePerson(Parent.BuyerParty, buyerParty.TaxIdentification);
            return buyerParty;
        }


        /// <summary>
        /// Se utiliza para formar el bloque de datos correspondientes a la partes, cuando el tipo de persona es Juríca
        /// </summary>
        /// <param name="parent">enumerado que indica cual de las tres partes llama al método, para saber de que controles tomar los datos</param>
        /// <returns>La estructura de LegalEntity completa con los datos tomados de la plantilla</returns>
        private LegalEntityType getLegalEntity(Parent parent)
        {
            LegalEntityType legalEntity = new LegalEntityType();
            string corporateName = "";
            ControlMessages msg = ControlMessages.getInstance();

            switch (parent)
            {


                case Parent.ThirdParty:

                    corporateName = this.datos.getValueByFieldName("TH_CorporateName");

                    if (string.IsNullOrEmpty(corporateName))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.TH_CorporateName).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    legalEntity.CorporateName = corporateName;
                    legalEntity.Item = getAddress(parent, this.datos.getValueByFieldName("TH_CountryCode"));
                    legalEntity.ContactDetails = getContacDetails(parent); break;

                case Parent.SellerParty:

                    corporateName = this.datos.getValueByFieldName("SP_CorporateName");

                    if (string.IsNullOrEmpty(corporateName))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.SP_CorporateName).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }

                    legalEntity.CorporateName = corporateName;
                    legalEntity.Item = getAddress(parent, this.datos.getValueByFieldName("SP_CountryCode"));
                    legalEntity.ContactDetails = getContacDetails(parent); break;

                case Parent.BuyerParty:

                    corporateName = this.datos.getValueByFieldName("BP_CorporateName");

                    if (string.IsNullOrEmpty(corporateName))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.BP_CorporateName).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }

                    legalEntity.CorporateName = corporateName;
                    legalEntity.Item = getAddress(parent, this.datos.getValueByFieldName("BP_CountryCode"));
                    legalEntity.ContactDetails = getContacDetails(parent); break;


            }

            return legalEntity;
        }


        /// <summary>
        /// Se utiliza para formar el bloque de datos correspondientes a la dirección de las partes, cuando el código de país es igual a  ESP
        /// </summary>
        /// <param name="parent">enumerado que indica cual de las tres partes llama al método, para saber de que controles tomar los datos</param>
        /// <returns>La estructura AddressType completa con los datos tomados de la plantilla</returns>
        private AddressType getAddressInSpain(Parent parent)
        {
            ControlMessages msg = ControlMessages.getInstance();

            AddressType addressInSpain = new AddressType(); //direccion en españa
            string address = "";
            string postCode = "";
            string town = "";
            string province = "";
            string countryCode = "";

            switch (parent)
            {
                case Parent.ThirdParty:

                    address = this.datos.getValueByFieldName("TH_Address");
                    postCode = this.datos.getValueByFieldName("TH_PostCode");
                    town = this.datos.getValueByFieldName("TH_Town");
                    province = this.datos.getValueByFieldName("TH_Province");
                    countryCode = this.datos.getValueByFieldName("TH_CountryCode");

                    if (string.IsNullOrEmpty(address))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.TH_Address).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    addressInSpain.Address = address;

                    if (string.IsNullOrEmpty(postCode))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.TH_PostCode).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }

                    addressInSpain.PostCode = postCode;

                    if (string.IsNullOrEmpty(town))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.TH_Town).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    addressInSpain.Town = town;

                    if (string.IsNullOrEmpty(province))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.TH_Province).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    addressInSpain.Province = province;

                    if (string.IsNullOrEmpty(countryCode))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.TH_CountryCode).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    addressInSpain.CountryCode = convertToCountryType(this.datos.getValueByFieldName("TH_CountryCode")); break;

                case Parent.SellerParty:

                    address = this.datos.getValueByFieldName("SP_Address");
                    postCode = this.datos.getValueByFieldName("SP_PostCode");
                    town = this.datos.getValueByFieldName("SP_Town");
                    province = this.datos.getValueByFieldName("SP_Province");
                    countryCode = this.datos.getValueByFieldName("SP_CountryCode");

                    if (string.IsNullOrEmpty(address))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.SP_Address).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    addressInSpain.Address = address;

                    if (string.IsNullOrEmpty(postCode))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.SP_PostCode).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    addressInSpain.PostCode = postCode;

                    if (string.IsNullOrEmpty(town))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.SP_Town).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    addressInSpain.Town = town;

                    if (string.IsNullOrEmpty(province))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.SP_Province).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    addressInSpain.Province = province;

                    if (string.IsNullOrEmpty(countryCode))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.SP_CountryCode).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    addressInSpain.CountryCode = convertToCountryType(this.datos.getValueByFieldName("SP_CountryCode")); break;

                case Parent.BuyerParty:

                    address = this.datos.getValueByFieldName("BP_Address");
                    postCode = this.datos.getValueByFieldName("BP_PostCode");
                    town = this.datos.getValueByFieldName("BP_Town");
                    province = this.datos.getValueByFieldName("BP_Province");
                    countryCode = this.datos.getValueByFieldName("BP_CountryCode");

                    if (string.IsNullOrEmpty(address))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.BP_Address).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    addressInSpain.Address = address;

                    if (string.IsNullOrEmpty(postCode))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.BP_PostCode).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    addressInSpain.PostCode = postCode;

                    if (string.IsNullOrEmpty(town))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.BP_Town).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    addressInSpain.Town = town;

                    if (string.IsNullOrEmpty(province))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.BP_Province).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    addressInSpain.Province = province;

                    if (string.IsNullOrEmpty(countryCode))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.BP_CountryCode).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    addressInSpain.CountryCode = convertToCountryType(this.datos.getValueByFieldName("BP_CountryCode")); break;

            }
            return addressInSpain;

        }

        /// <summary>
        /// Se utiliza para formar el bloque de datos correspondientes a la dirección de las partes, cuando el código de país es diferente a ESP
        /// </summary>
        /// <param name="parent">enumerado que indica cual de las tres partes llama al método, para saber de que controles tomar los datos</param>
        /// <returns>La estructura AddressType completa con los datos tomados de la plantilla</returns>
        private OverseasAddressType getOverSeasAddres(Parent parent)
        {
            ControlMessages msg = ControlMessages.getInstance();

            OverseasAddressType overSeasAddress = new OverseasAddressType(); //direccion en el extranjero
            string address = "";
            string postCode = "";
            string town = "";
            string province = "";
            string countryCode = "";

            switch (parent)
            {
                case Parent.ThirdParty:

                    address = this.datos.getValueByFieldName("TH_Address");
                    postCode = this.datos.getValueByFieldName("TH_PostCode");
                    town = this.datos.getValueByFieldName("TH_Town");
                    province = this.datos.getValueByFieldName("TH_Province");
                    countryCode = this.datos.getValueByFieldName("TH_CountryCode");

                    if (string.IsNullOrEmpty(address))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.TH_Address).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    overSeasAddress.Address = address;

                    if (string.IsNullOrEmpty(postCode) || string.IsNullOrEmpty(town))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.TH_PostCode).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    overSeasAddress.PostCodeAndTown = postCode + town;

                    if (string.IsNullOrEmpty(province))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.TH_Province).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    overSeasAddress.Province = province;

                    if (string.IsNullOrEmpty(countryCode))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.TH_CountryCode).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    overSeasAddress.CountryCode = convertToCountryType(this.datos.getValueByFieldName("TH_CountryCode")); break;


                case Parent.SellerParty:

                    address = this.datos.getValueByFieldName("SP_Address");
                    postCode = this.datos.getValueByFieldName("SP_PostCode");
                    town = this.datos.getValueByFieldName("SP_Town");
                    province = this.datos.getValueByFieldName("SP_Province");
                    countryCode = this.datos.getValueByFieldName("SP_CountryCode");

                    if (string.IsNullOrEmpty(address))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.SP_Address).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    overSeasAddress.Address = address;

                    if (string.IsNullOrEmpty(postCode) || string.IsNullOrEmpty(town))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.SP_PostCode).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    overSeasAddress.PostCodeAndTown = postCode + town;

                    if (string.IsNullOrEmpty(province))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.SP_Province).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    overSeasAddress.Province = province;

                    if (string.IsNullOrEmpty(countryCode))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.SP_CountryCode).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    overSeasAddress.CountryCode = convertToCountryType(this.datos.getValueByFieldName("SP_CountryCode")); break;

                case Parent.BuyerParty:

                    address = this.datos.getValueByFieldName("BP_Address");
                    postCode = this.datos.getValueByFieldName("BP_PostCode");
                    town = this.datos.getValueByFieldName("BP_Town");
                    province = this.datos.getValueByFieldName("BP_Province");
                    countryCode = this.datos.getValueByFieldName("BP_CountryCode");

                    if (string.IsNullOrEmpty(address))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.BP_Address).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    overSeasAddress.Address = address;

                    if (string.IsNullOrEmpty(postCode) || string.IsNullOrEmpty(town))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.BP_PostCode).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    overSeasAddress.PostCodeAndTown = postCode + town;

                    if (string.IsNullOrEmpty(province))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.BP_Province).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    overSeasAddress.Province = province;

                    if (string.IsNullOrEmpty(countryCode))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.BP_CountryCode).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    overSeasAddress.CountryCode = convertToCountryType(this.datos.getValueByFieldName("BP_CountryCode")); break;

            }
            return overSeasAddress;

        }

        /// <summary>
        /// Determina con base en el código de país, el tipo de dirección correspondiente a cada una de las partes
        /// </summary>
        /// <param name="parent">enumerado que indica cual de las tres partes llama al método, para saber de que controles tomar los datos</param>
        /// <param name="countryCode">código de país</param>
        /// <returns>return un objeto que puedo ser de tipo addressType ó OverSeasAddressType que contiene los datos de la direcciona</returns>
        private object getAddress(Parent parent, string countryCode)
        {

            object address = null;

            if (countryCode.Equals(CountryType.ESP.ToString("g")))
                address = getAddressInSpain(parent);
            else
                address = getOverSeasAddres(parent);

            return address;

        }

        /// <summary>
        /// Se encarga de completar el bloque de datos correspondientes a la información de contacto de las partes
        /// </summary>
        /// <param name="parent"> enumerado que indica cual de las tres partes llama al método, para saber de que controles tomar los datos</param>
        /// <returns>Un objeto ContactDetailsType completo con los datos tomados de la plantilla</returns>
        private ContactDetailsType getContacDetails(Parent parent)
        {
            ContactDetailsType contactDetails = null;
            string tel = "";
            string email = "";


            switch (parent)
            {
                case Parent.ThirdParty:

                    tel = this.datos.getValueByFieldName("TH_Telephone");
                    email = this.datos.getValueByFieldName("TH_Email");

                    if (!string.IsNullOrEmpty(tel) || !string.IsNullOrEmpty(email))
                    {
                        contactDetails = new ContactDetailsType();
                        contactDetails.Telephone = tel;
                        contactDetails.ElectronicMail = email;
                    }

                    break;

                case Parent.SellerParty:

                    tel = this.datos.getValueByFieldName("SP_Telephone");
                    email = this.datos.getValueByFieldName("SP_Email");

                    if (!string.IsNullOrEmpty(tel) || !string.IsNullOrEmpty(email))
                    {
                        contactDetails = new ContactDetailsType();
                        contactDetails.Telephone = tel;
                        contactDetails.ElectronicMail = email;
                    }

                    break;

                case Parent.BuyerParty:

                    tel = this.datos.getValueByFieldName("BP_Telephone");
                    email = this.datos.getValueByFieldName("BP_Email");

                    if (!string.IsNullOrEmpty(tel) || !string.IsNullOrEmpty(email))
                    {
                        contactDetails = new ContactDetailsType();
                        contactDetails.Telephone = tel;
                        contactDetails.ElectronicMail = email;
                    }

                    break;


            }
            return contactDetails;
        }

        /// <summary>
        /// Se utiliza para formar el bloque de datos correspondientes a la partes, cuando el tipo de persona es Física
        /// </summary>
        /// <param name="parent">enumerado que indica cual de las tres partes llama al método, para saber de que controles tomar los datos</param>
        /// <returns>El Objeto de Tipo IndividualType completo con los datos tomados de la plantilla</returns>
        private IndividualType getIndividual(Parent parent)
        {
            IndividualType individual = new IndividualType();
            ControlMessages msg = ControlMessages.getInstance();

            string name = "";
            string Fname = "";

            switch (parent)
            {

                case Parent.ThirdParty:

                    name = this.datos.getValueByFieldName("TH_Name");
                    Fname = this.datos.getValueByFieldName("TH_FirstSurname");

                    if (string.IsNullOrEmpty(name))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.TH_Name).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    individual.Name = name;

                    if (string.IsNullOrEmpty(Fname))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.TH_FirstSurname).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    individual.FirstSurname = Fname;

                    individual.SecondSurname = this.datos.getValueByFieldName("TH_SecondSurname");
                    individual.Item = getAddress(parent, this.datos.getValueByFieldName("TH_CountryCode"));
                    individual.ContactDetails = getContacDetails(parent); break;

                case Parent.SellerParty:

                    name = this.datos.getValueByFieldName("SP_Name");
                    Fname = this.datos.getValueByFieldName("SP_FirstSurname");

                    if (string.IsNullOrEmpty(name))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.SP_Name).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    individual.Name = name;

                    if (string.IsNullOrEmpty(Fname))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.SP_FirstSurname).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    individual.FirstSurname = Fname;

                    individual.SecondSurname = this.datos.getValueByFieldName("SP_SecondSurname");
                    individual.Item = getAddress(parent, this.datos.getValueByFieldName("SP_CountryCode"));
                    individual.ContactDetails = getContacDetails(parent); break;

                case Parent.BuyerParty:

                    name = this.datos.getValueByFieldName("BP_Name");
                    Fname = this.datos.getValueByFieldName("BP_FirstSurname");

                    if (string.IsNullOrEmpty(name))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.BP_Name).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    individual.Name = name;

                    if (string.IsNullOrEmpty(Fname))
                    {
                        Globals.ThisAddIn.getControlByTag(ControlList.Tag.BP_FirstSurname).Range.Select();
                        throw new Exception(msg.getMessage("MsgIncompleteData"));
                    }
                    individual.FirstSurname = Fname;

                    individual.SecondSurname = this.datos.getValueByFieldName("BP_SecondSurname");
                    individual.Item = getAddress(parent, this.datos.getValueByFieldName("BP_CountryCode"));
                    individual.ContactDetails = getContacDetails(parent); break;

            }
            return individual;
        }

        /// <summary>
        /// Determina la  información a completar de las partes segun el tipo de persona
        /// </summary>
        /// <param name="parent">Enumerado que indica cual de las tres partes llama al método para saber de que controles tomar los datos</param>
        /// <param name="taxIdentification">objeto que contiene el tipo de persona de las partes</param>
        /// <returns>un objeto con los datos de las partes, que puede ser de tipo IndividualType, ó LegalEntityType</returns>
        private object getTypePerson(Parent parent, TaxIdentificationType taxIdentification)
        {
            if (!taxIdentification.Equals(null))
            {
                if (taxIdentification.PersonTypeCode.Equals(PersonTypeCodeType.J))

                    return getLegalEntity(parent);
                else
                    return getIndividual(parent);
            }
            return null;
        }

        /// <summary>
        /// Se encarga de formar las estructura Batch
        /// </summary>
        /// <returns>un objeto de tipo de BatchType completo con datos generados a partir de la plantilla</returns>
        private BatchType getBatch()
        {
            ControlMessages msg = ControlMessages.getInstance();

            batch = new BatchType();
            string id = string.Concat(facturae.Parties.SellerParty.TaxIdentification.TaxIdentificationNumber, facturae.Invoices[0].InvoiceHeader.InvoiceNumber, facturae.Invoices[0].InvoiceHeader.InvoiceSeriesCode);
            batch.BatchIdentifier = id;

            string currencyCode = this.datos.getValueByFieldName("InvIssue_InvoiceCurrencyCode");
            if (string.IsNullOrEmpty(currencyCode))
            {
                Globals.ThisAddIn.getControlByTag(ControlList.Tag.InvIssue_InvoiceCurrencyCode).Range.Select();
                throw new Exception(msg.getMessage("MsgIncompleteData"));
            }
            batch.InvoiceCurrencyCode = convertToCurrencyType(this.datos.getValueByFieldName("InvIssue_InvoiceCurrencyCode"));

            batch.InvoicesCount = 1;

            AmountType at = new AmountType();

            at.TotalAmount = String.Format(culturaFactura.NumberFormat, "{0:0.00}", calculos.totalAmount);

            if (!moneda.Equals(CurrencyCodeType.EUR)) 
            {
                at.EquivalentInEurosSpecified = true;
                at.EquivalentInEuros = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (calculos.totalAmount * exchangeRate));
            }

            batch.TotalInvoicesAmount = at;
            batch.TotalOutstandingAmount = at;
            batch.TotalExecutableAmount = at;

            return batch;
        }

        /// <summary>
        /// Se encarga de formar el bloque de datos InvoiceIssueData que contiene los datos de emision de la factura 
        /// </summary>
        /// <returns>un objeto de tipo InvoiceIssueDataType generado con los datos de la plantilla</returns>
        private InvoiceIssueDataType getInvoiceIssueData()
        {
            invoiceIssueData = new InvoiceIssueDataType();
            ControlMessages msg = ControlMessages.getInstance();

            string issueDate = this.datos.getValueByFieldName("InvIssue_IssueDate");
            if (string.IsNullOrEmpty(issueDate))
            {
                Globals.ThisAddIn.getControlByTag(ControlList.Tag.InvIssue_IssueDate).Range.Select();
                throw new Exception(msg.getMessage("MsgIncompleteData"));
            }

            try
            {
                //CultureInfo cult = new CultureInfo("es-ES");
                invoiceIssueData.IssueDate = DateTime.Parse(issueDate, culturaOffice);

                string operationDate = this.datos.getValueByFieldName("InvIssue_OperationDate");

                if (!string.IsNullOrEmpty(operationDate))
                {
                    if (!invoiceIssueData.IssueDate.Equals(DateTime.Parse(operationDate, culturaOffice)))
                    {
                        invoiceIssueData.OperationDateSpecified = true;
                        invoiceIssueData.OperationDate = DateTime.Parse(operationDate, culturaOffice);
                    }
                }

                //invoiceIssueData.PlaceOfIssue = getPlaceOfIssue(true);
            }
            catch (Exception)
            {
                //ControlMessages msg = ControlMessages.getInstance();
                throw new Exception(msg.getMessage(ControlMessages.Msg.ErrorIssuedDate));
            }

            try
            {
                invoiceIssueData.PlaceOfIssue = getPlaceOfIssue(false);
            }
            catch (Exception e) { throw e; }

            try
            {
                invoiceIssueData.InvoicingPeriod = getInvoicingPeriod();
            }
            catch (Exception) { }

            invoiceIssueData.InvoiceCurrencyCode = convertToCurrencyType(this.datos.getValueByFieldName("InvIssue_InvoiceCurrencyCode"));
            invoiceIssueData.ExchangeRateDetails = getExchangeRateDetails();
            invoiceIssueData.TaxCurrencyCode = convertToCurrencyType(this.datos.getValueByFieldName("InvIssue_TaxCurrencyCode"));
            invoiceIssueData.LanguageName = convertToLanguageCodeType(this.datos.getValueByFieldName("InvIssue_LanguageName"));

            return invoiceIssueData;



        }

        private ExchangeRateDetailsType getExchangeRateDetails()
        {
            try
            {

                ExchangeRateDetailsType exchangeRateDetails = null;
                if (!invoiceIssueData.InvoiceCurrencyCode.Equals(CurrencyCodeType.EUR))
                {
                    exchangeRateDetails.ExchangeRate = this.datos.getValueByFieldName("InvIssue_ExchangeRateDetails_ExchangeRate");
                    exchangeRateDetails.ExchangeRateDate = DateTime.Parse(this.datos.getValueByFieldName("InvIssue_ExchangeRateDetails_ExchangeRateDate"), culturaOffice);
                }

                return exchangeRateDetails;
            }
            catch (Exception) { return null; }
        }

        private PlaceOfIssueType getPlaceOfIssue(bool enable)
        {
            PlaceOfIssueType placeOfIssue = null;
            try
            {
                if (enable)
                {
                    placeOfIssue = new PlaceOfIssueType();
                    placeOfIssue.PostCode = this.datos.getValueByFieldName("SP_PostCode");
                    placeOfIssue.PlaceOfIssueDescription = "";
                }
                return placeOfIssue;
            }
            catch (Exception)
            {
                ControlMessages msg = ControlMessages.getInstance();
                throw new Exception(msg.getMessage(ControlMessages.Msg.ErrorPostCode));
            }
        }

        /// <summary>
        /// Se encarga de formar el bloque de datos PeriodDates que especifica el periodo de tributación
        /// </summary>
        /// <returns>Un objeto con las fechas de inicio y finalización del periodo de tributación</returns>
        private PeriodDates getInvoicingPeriod()
        {
            try
            {
                PeriodDates invoicingPeriod = null;
                if (invoiceHeader != null)
                {
                    if (invoiceHeader.InvoiceClass.Equals(InvoiceClassType.OC) || invoiceHeader.InvoiceClass.Equals(InvoiceClassType.CC))
                    {
                        invoicingPeriod = new PeriodDates();
                        invoicingPeriod.StartDate = DateTime.Parse(this.datos.getValueByFieldName("InvIssue_InvoicingPeriod_StartDate"), culturaOffice);
                        invoicingPeriod.EndDate = DateTime.Parse(this.datos.getValueByFieldName("InvIssue_InvoicingPeriod_EndDate"),culturaOffice);
                    }

                }
                return invoicingPeriod;
            }
            catch (Exception)
            {
                ControlMessages msg = ControlMessages.getInstance();
                throw new Exception(msg.getMessage(ControlMessages.Msg.ErrorInvoicingPeriod));
            }
        }

        /// <summary>
        /// Se encarga de formar el bloque de datos del encabezado de la factura
        /// </summary>
        /// <returns>un objeto InvoiceHeaderType que contiene el numero y serie de la factura, asi como los datos de rectificación
        /// en caso de la factura sea rectificativa</returns>
        private InvoiceHeaderType getInvoiceHeader()
        {
            ControlMessages msg = ControlMessages.getInstance();

            invoiceHeader = new InvoiceHeaderType();

            string invoiceNumber = this.datos.getValueByFieldName("IH_InvoiceNumber");
            string invoiceSerieCode = this.datos.getValueByFieldName("IH_InvoiceSeriesCode");
            string invoiceclass = this.datos.getValueByFieldName("IH_InvoiceClass");

            if (string.IsNullOrEmpty(invoiceNumber))
            {
                Globals.ThisAddIn.getControlByTag(ControlList.Tag.IH_InvoiceNumber).Range.Select();
                throw new Exception(msg.getMessage("MsgIncompleteData"));
            }
            invoiceHeader.InvoiceNumber = invoiceNumber;

            if (string.IsNullOrEmpty(invoiceSerieCode))
            {
                Globals.ThisAddIn.getControlByTag(ControlList.Tag.IH_InvoiceSeriesCode).Range.Select();
                throw new Exception(msg.getMessage("MsgIncompleteData"));
            }
            invoiceHeader.InvoiceSeriesCode = this.datos.getValueByFieldName("IH_InvoiceSeriesCode");
            invoiceHeader.InvoiceDocumentType = convertToInvoiceDocumentType(this.datos.getValueByFieldName("IH_InvoiceDocumentType"));

            if (string.IsNullOrEmpty(invoiceclass))
            {
                Globals.ThisAddIn.getControlByTag(ControlList.Tag.IH_InvoiceClass).Range.Select();
                throw new Exception(msg.getMessage("MsgIncompleteData"));
            }

            invoiceHeader.InvoiceClass = convertToInvoiceClassType(this.datos.getValueByFieldName("IH_InvoiceClass"));

            if (invoiceHeader.InvoiceClass.Equals(InvoiceClassType.OR))
            {
                invoiceHeader.Corrective = getCorrective();
            }

            return invoiceHeader;
        }

        /// <summary>
        /// Define el bloque de datos de rectificación de una factura, se utiliza solo cuando el invoiceClass = OR ó CR
        /// </summary>
        /// <returns>Un objeto de tipo CorrectiveType con el numero y serie de la factura nueva, el número y serie de la 
        /// factura a rectificar, así como el motivo y método de rectificación</returns>
        private CorrectiveType getCorrective()
        {
            ControlMessages msg = ControlMessages.getInstance();

            CorrectiveType corrective = null;

            try
            {

                if (invoiceHeader != null)
                {
                    if (invoiceHeader.InvoiceClass.Equals(InvoiceClassType.OR) || invoiceHeader.InvoiceClass.Equals(InvoiceClassType.CR))
                    {
                        corrective = new CorrectiveType();
                        corrective.InvoiceNumber = this.datos.getValueByFieldName("CORR_InvoiceNumber");
                        corrective.InvoiceSeriesCode = this.datos.getValueByFieldName("CORR_InvoiceSeriesCode");


                        string reason = this.datos.getValueByFieldName("CORR_ReasonDescription");

                        if (string.IsNullOrEmpty(reason))
                        {
                            Globals.ThisAddIn.getControlByTag(ControlList.Tag.CORR_ReasonDescription).Range.Select();
                            throw new Exception(msg.getMessage("MsgIncompleteData"));
                        }

                        corrective.ReasonCode = convertToReasonCodeType("9");
                        corrective.ReasonDescription = reason;


                        corrective.TaxPeriod = new PeriodDates();
                        //CultureInfo cult = new CultureInfo("es-ES");
                        corrective.TaxPeriod.StartDate = DateTime.Parse(this.datos.getValueByFieldName("CORR_TaxPeriod_StartDate"), culturaOffice);
                        corrective.TaxPeriod.EndDate = DateTime.Parse(this.datos.getValueByFieldName("CORR_TaxPeriod_EndDate"), culturaOffice);

                        string correctiveMethood = this.datos.getValueByFieldName("CORR_CorrectionMethodDescription");

                        if (string.IsNullOrEmpty(correctiveMethood))
                        {
                            Globals.ThisAddIn.getControlByTag(ControlList.Tag.CORR_CorrectionMethodDescription).Range.Select();
                            throw new Exception(msg.getMessage("MsgIncompleteData"));
                        }

                        corrective.CorrectionMethod = convertToCorrectionMethodType(this.datos.getValueByFieldName("CORR_CorrectionMethodDescription_Value"));
                        corrective.CorrectionMethodDescription = correctiveMethood;

                    }
                }
            }
            catch (Exception exc) { throw exc; }

            return corrective;
        }

        /// <summary>
        /// Forma la estructura que contiene la Información adicional de la factura, como por ejemplo las observaciones
        /// </summary>
        /// <returns>un objeto de tipo AdditionalDataType</returns>
        private AdditionalDataType getAdditionaData()
        {
            ControlMessages msg = ControlMessages.getInstance();

            enumerateTables();
            AdditionalDataType additionalData = null;
            try
            {

                if (control != null)
                {

                    additionalData = new AdditionalDataType();
                    string EInvoiceInfo = "\n" + msg.getMessage(ControlMessages.Msg.MsgElectronic);
                    if (paperInvoice)
                        EInvoiceInfo = "\n" + msg.getMessage(ControlMessages.Msg.MsgPaper);

                    string additData = document.Tables[t4].Rows[2].Range.Text.Trim(x).Trim();

                    if (additData.Contains(EInvoiceInfo.Trim(x).Trim()))
                    {
                        int LastIndex = additData.Length - EInvoiceInfo.Trim().Length;
                        if (LastIndex > 0)
                        {
                            additData = additData.Substring(0, LastIndex);
                        }
                        else
                            additData = "";

                    }

                    additData += EInvoiceInfo;

                    additionalData.InvoiceAdditionalInformation = additData;
                    document.Tables[t4].Rows[2].Range.Text = additData;
                }
            }
            catch (Exception) { return additionalData; }
            return additionalData;

        }

        /// <summary>
        /// Define la estructura que contiene la información referentes al pago de la factura
        /// </summary>
        /// <param name="paymentDetails">Lista de medios de pago de la factura, ya que puede ser más de uno</param>
        /// <returns>Lista de Objetos de tipo InstallmentType, con la información del pago </returns>
        private List<InstallmentType> getPaymentDetails(List<InstallmentType> paymentDetails)
        {
            if (paymentDetails == null)
                paymentDetails = new List<InstallmentType>();
            InstallmentType installment = new InstallmentType();
            //CultureInfo cult = new CultureInfo("es-ES");
            string InstDueDate = this.datos.getValueByFieldName("Inst_InstallmentDueDate");
            installment.InstallmentDueDate = DateTime.Parse(InstDueDate, culturaOffice);
            installment.InstallmentAmount = this.datos.getValueByFieldName("Inst_InstallmentAmount");
            installment.PaymentMeans = this.datos.getValueByFieldName("Inst_PaymentMeans");

            paymentDetails.Add(installment);

            return paymentDetails;

        }

        private List<DeliveryNoteType> getDeliveryNotes(List<DeliveryNoteType> deliveryNotes)
        {
            if (deliveryNotes == null)
                deliveryNotes = new List<DeliveryNoteType>();
            DeliveryNoteType deliveryNote = new DeliveryNoteType();
            deliveryNotes.Add(deliveryNote);
            return deliveryNotes;

        }

        #endregion

        #region calculos


        /// <summary>
        /// Realiza los cálculos para los totales del bloque Batch
        /// </summary>
        /// <param name="parent">identifica al llamador del método para definir que operación realizar</param>
        /// <returns>El resultado de la operacion, y si aplica, la equivalencia en euros en caso</returns>
        private AmountType getAmount(Parent parent)
        {
            AmountType totalAmount = new AmountType();

            switch (parent)
            {
                case Parent.BatchTIA:

                    totalAmount.TotalAmount = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (((totalGrossAmount - totalGeneralDiscounts) + TotalTaxesOutputs) - TotalTaxesWithHeld));


                    if (!moneda.Equals(CurrencyCodeType.EUR))
                    {
                        totalAmount.EquivalentInEurosSpecified = true;
                        totalAmount.EquivalentInEuros = String.Format(culturaFactura.NumberFormat, "{0:0.00}", ((((totalGrossAmount - totalGeneralDiscounts) + TotalTaxesOutputs) - TotalTaxesWithHeld) * exchangeRate));

                    }

                    break;

                case Parent.BatchTOA:

                    totalAmount.TotalAmount = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (((totalGrossAmount - totalGeneralDiscounts) + TotalTaxesOutputs) - TotalTaxesWithHeld));



                    if (!moneda.Equals(CurrencyCodeType.EUR))
                    {
                        totalAmount.EquivalentInEurosSpecified = true;
                        totalAmount.EquivalentInEuros = String.Format(culturaFactura.NumberFormat, "{0:0.00}", ((((totalGrossAmount - totalGeneralDiscounts) + TotalTaxesOutputs) - TotalTaxesWithHeld) * exchangeRate));

                    }

                    break;

                case Parent.BatchTEA:

                    totalAmount.TotalAmount = String.Format(culturaFactura.NumberFormat, "{0:0.00}", ((((totalGrossAmount - totalGeneralDiscounts) + TotalTaxesOutputs) - TotalTaxesWithHeld)));


                    if (!moneda.Equals(CurrencyCodeType.EUR))
                    {
                        totalAmount.EquivalentInEurosSpecified = true;
                        totalAmount.EquivalentInEuros = String.Format(culturaFactura.NumberFormat, "{0:0.00}", ((((totalGrossAmount - totalGeneralDiscounts) + TotalTaxesOutputs) - TotalTaxesWithHeld) * exchangeRate));

                    }

                    break;
            }
            return totalAmount;
        }


        /// <summary>
        /// LLama a los métodos encargados de formar  la estructura de la factura
        /// </summary>
        /// <returns>El bloque de Facturae correspondiente a la factura</returns>
        private InvoiceType getInvoice()
        {
           
            try
            {
                invoice = new InvoiceType();
                invoice.InvoiceHeader = getInvoiceHeader();
                invoice.InvoiceIssueData = getInvoiceIssueData();
                invoice.Items = computeDetails(invoice.Items);
                invoice.TaxesOutputs = getTaxesO(invoice.TaxesOutputs);
                invoice.TaxesWithheld = getTaxesW(invoice.TaxesWithheld);
                invoice.InvoiceTotals = getTotals();
                invoice.AdditionalData = getAdditionaData();

            }
            catch (Exception e)
            {
                throw e;
            }
            return invoice;
        }


        private List<InvoiceLineType> computeDetails(List<InvoiceLineType> items)
        {
            if (this.document == null)
            {
                this.document = Globals.ThisAddIn.Application.ActiveDocument;
            }

            if (document.Tables[t2].Rows.Count > 3)
            {

                int rowcount = this.document.Tables[t2].Rows.Count - 1;

                object[,] detailrows = new object[rowcount - 2, 7];

                for (int i = 3; i <= rowcount; i++)
                {
                    detailrows[i - 3, 0] = this.document.Tables[t2].Rows[i].Cells[1].Range.Text.Trim(x).Trim();
                    detailrows[i - 3, 1] = this.document.Tables[t2].Rows[i].Cells[2].Range.Text.Trim(x).Trim();
                    detailrows[i - 3, 2] = this.document.Tables[t2].Rows[i].Cells[3].Range.Text.Trim(x).Trim();
                    detailrows[i - 3, 3] = this.document.Tables[t2].Rows[i].Cells[4].Range.Text.Trim(x).Trim();
                    detailrows[i - 3, 4] = this.document.Tables[t2].Rows[i].Cells[5].Range.Text.Trim(x).Trim();
                    detailrows[i - 3, 5] = this.document.Tables[t2].Rows[i].Cells[6].Range.Text.Trim(x).Trim();
                    detailrows[i - 3, 6] = this.document.Tables[t2].Rows[i].Cells[7].Range.Text.Trim(x).Trim();
                }

                object[,] resultdetails = calculos.computeDetails(detailrows);

                if (items == null)
                    items = new List<InvoiceLineType>();


                for (int i = 0; i < resultdetails.GetLength(0); i++)
                {

                    //CultureInfo cult = new CultureInfo("es-ES");
                    InvoiceLineType item = new InvoiceLineType();

                    DateTime transactionDate = DateTime.Parse(resultdetails[i, 0].ToString(), culturaOffice);
                    string description = resultdetails[i, 1].ToString();
                    string quantity = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (double)resultdetails[i, 2]);
                    string price = String.Format(culturaFactura.NumberFormat, "{0:0.000000}", (double)resultdetails[i, 3]);
                    string discountRate = String.Format(culturaFactura.NumberFormat, "{0:0.0000}", (double)resultdetails[i, 5]);
                    string totalAmount = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (double)resultdetails[i, 7]);
                    string taxRate = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (double)resultdetails[i, 8]);
                    string TaxWRate = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (double)resultdetails[i, 9]);
                    string baseimp = String.Empty;
                    string cost = String.Empty;
                    string discamount = String.Empty;

                    if (this.facturaeVersion.Equals(InvoceTypes.FACTURAE_3_1))
                    {
                        baseimp = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (double)resultdetails[i, 7]);
                        cost = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (double)resultdetails[i, 4]);
                        discamount = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (double)resultdetails[i, 6]);
                    }
                    else
                    {
                        baseimp = String.Format(culturaFactura.NumberFormat, "{0:0.000000}", (double)resultdetails[i, 7]);
                        cost = String.Format(culturaFactura.NumberFormat, "{0:0.000000}", (double)resultdetails[i, 4]);
                        discamount = String.Format(culturaFactura.NumberFormat, "{0:0.000000}", (double)resultdetails[i, 6]);
                    }


                    item.TransactionDateSpecified = true;
                    item.TransactionDate = transactionDate;
                    item.ItemDescription = description;
                    item.Quantity = quantity;
                    item.UnitPriceWithoutTax = price;
                    item.TotalCost = cost;
                    item.GrossAmount = baseimp;


                    //descuentos por linea 

                    if (double.Parse(discountRate) > 0)
                    {
                        DiscountType discountByLine = new DiscountType();
                        discountByLine.DiscountReason = "discount";
                        discountByLine.DiscountRate = discountRate;
                        discountByLine.DiscountAmount = discamount;
                        discountByLine.DiscountRateSpecified = true;
                        item.DiscountsAndRebates = new List<DiscountType>();
                        item.DiscountsAndRebates.Add(discountByLine);

                    }
                    else
                    {
                        item.DiscountsAndRebates = null;
                    }

                    //impuestos por linea
                    InvoiceLineTypeTax tax = new InvoiceLineTypeTax();
                    tax.TaxTypeCode = TaxTypeCodeType.Item01;
                    tax.TaxRate = taxRate;
                    tax.TaxableBase = new AmountType();
                    tax.TaxableBase.TotalAmount = totalAmount;

                    if (!moneda.Equals(CurrencyCodeType.EUR))
                    {
                        tax.TaxableBase.EquivalentInEurosSpecified = true;
                        tax.TaxableBase.EquivalentInEuros = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (double.Parse(totalAmount, culturaFactura.NumberFormat) * exchangeRate));
                    }

                    item.TaxesOutputs = new List<InvoiceLineTypeTax>();
                    item.TaxesOutputs.Add(tax);

                    //impuestos retenidos 
                    //if ((double)resultdetails[i, 6] > 0)
                    if (double.Parse(TaxWRate) > 0)
                    {
                        TaxType taxW = new TaxType();
                        taxW.TaxTypeCode = TaxTypeCodeType.Item04;
                        taxW.TaxRate = TaxWRate;
                        taxW.TaxableBase = new AmountType();
                        taxW.TaxableBase.TotalAmount = totalAmount;

                        if (!moneda.Equals(CurrencyCodeType.EUR))
                        {
                            taxW.TaxableBase.EquivalentInEurosSpecified = true;
                            taxW.TaxableBase.EquivalentInEuros = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (double.Parse(totalAmount, culturaFactura.NumberFormat) * exchangeRate));
                        }

                        item.TaxesWithheld = new List<TaxType>();
                        item.TaxesWithheld.Add(taxW);

                    }
                    else
                    {
                        item.TaxesWithheld = null;
                    }

                    items.Add(item);

                    //totalGrossAmount += double.Parse(item.GrossAmount, numberFormat);
                    //TotalTaxesOutputs += Round3(montoImp, 2);
                    //TotalTaxesWithHeld += Round3(IRPFAmount, 2);
                    //GeneralDiscountBase = double.Parse(string.Format(num, "{0:0.00}", totalGrossAmount));


                }
            }
            else
            {
                ControlMessages controlM = ControlMessages.getInstance();

                throw new Exception(controlM.getMessage(ControlMessages.Msg.ErrorInvoiceHaveNotDetails));
            }

            return items;

        }

        private InvoiceTotalsType getTotals()
        {
            InvoiceTotalsType invoiceTotals = new InvoiceTotalsType();

            invoiceTotals.GeneralDiscounts = computeDiscounts(invoiceTotals.GeneralDiscounts);

            string tga = String.Format(culturaFactura.NumberFormat, "{0:0.00}", calculos.totalGrossAmount);
            string tgd = String.Format(culturaFactura.NumberFormat, "{0:0.00}", calculos.totalGeneralDiscount);
            string tgabt = String.Format(culturaFactura.NumberFormat, "{0:0.00}", calculos.totalGrossAmountBeforeTaxes);
            string tto = String.Format(culturaFactura.NumberFormat, "{0:0.00}", calculos.totalTaxesOutputs);
            string ttw = String.Format(culturaFactura.NumberFormat, "{0:0.00}", calculos.totalTaxesWithHeld);
            string invoiceTotal = String.Format(culturaFactura.NumberFormat, "{0:0.00}", calculos.totalAmount);

            invoiceTotals.TotalGrossAmount = tga;


            if (invoiceTotals.GeneralDiscounts != null)
            {
                invoiceTotals.TotalGeneralDiscounts = tgd;
            }
            else
            {
                invoiceTotals.TotalGeneralDiscounts = null;
            }

            invoiceTotals.TotalGeneralDiscountsSpecified = true;
            invoiceTotals.TotalGrossAmountBeforeTaxes = tgabt;
            invoiceTotals.TotalTaxOutputs = tto;
            invoiceTotals.TotalTaxesWithheld = ttw;
            invoiceTotals.InvoiceTotal = invoiceTotal;
            invoiceTotals.TotalOutstandingAmount = invoiceTotal;
            invoiceTotals.TotalExecutableAmount = invoiceTotal;

            return invoiceTotals;
        }


        private List<DiscountType> computeDiscounts(List<DiscountType> generalDiscounts)
        {
            if (this.document == null)
            {
                this.document = Globals.ThisAddIn.Application.ActiveDocument;
            }

            if (document.Tables[t3].Rows.Count > 3)
            {
                int rowcount = this.document.Tables[t3].Rows.Count - 1;

                if (generalDiscounts == null)
                    generalDiscounts = new List<DiscountType>();

                object[,] discountRows = new object[rowcount - 2, 2];


                for (int i = 3; i <= rowcount; i++)
                {
                    discountRows[i - 3, 0] = this.document.Tables[t3].Rows[i].Cells[1].Range.Text.Trim(x).Trim();
                    discountRows[i - 3, 1] = this.document.Tables[t3].Rows[i].Cells[2].Range.Text.Trim(x).Trim();
                }

                object[,] results = calculos.computeDiscount(discountRows);

                for (int i = 0; i < results.GetLength(0); i++)
                {
                    string reason = results[i, 0].ToString();
                    double discountRate = (double)results[i, 1];
                    double discountAmount = (double)results[i, 2];
                    generalDiscounts.Add(getDiscount(reason, discountRate, discountAmount));
                }

            }
            else
            {
                generalDiscounts = null;
            }

            return generalDiscounts;
        }

        /// <summary>
        /// Método utilizado por el método getGeneralDiscounts() para registrar nuevos tipos de descuento
        /// </summary>
        /// <param name="discountRate">Porcentaje de descuento a aplicar sobre el importe total bruto</param>
        /// <param name="discountAmount">Importe a descontar</param>
        /// <returns>un objeto DiscountType que con la información pasada por parámetros</returns>
        private DiscountType getDiscount(string discountReason, double discountRate, double discountAmount)
        {
            DiscountType discount = new DiscountType();
            discount.DiscountReason = discountReason;

            object[] tx = { discountRate };
            discount.DiscountRate = String.Format(culturaFactura.NumberFormat, "{0:0.0000}", tx);
            if (this.facturaeVersion.Equals(InvoceTypes.FACTURAE_3_1))
            {
                discount.DiscountAmount = String.Format(culturaFactura.NumberFormat, "{0:0.00}", discountAmount);
            }
            else
            {
                discount.DiscountAmount = String.Format(culturaFactura.NumberFormat, "{0:0.000000}", discountAmount);
            }
            discount.DiscountRateSpecified = true;

            return discount;
        }

        private List<TaxOutputType> getTaxesO(List<TaxOutputType> taxesOutputs)
        {

            if (taxesOutputs == null)
                taxesOutputs = new List<TaxOutputType>();

            List<Taxes> taxesList = calculos.taxes.TaxesList;

            foreach (Taxes tax in taxesList)
            {
                taxesOutputs.Add(getTax(tax.Taxablebase, double.Parse(tax.TaxType, culturaOffice.NumberFormat), tax.Taxamount));
            }

            return taxesOutputs;
        }

        /// <summary>
        /// Método utilizado por getTaxesOutputs(), para registrar nuevos tipos de impuestos repercutidos
        /// </summary>
        /// <param name="baseImp">Base imponible sobre la que que se aplicarán los impuestos</param>
        /// <param name="taxRate">Porcentaje de impuesto a aplicar</param>
        /// <param name="montoImp">Importe del impuesto</param>
        /// <returns>Un objeto TaxOutputType que contiene la información del nuevo impuesto</returns>
        private TaxOutputType getTax(double baseImp, double taxRate, double montoImp)
        {
            TaxOutputType tax = new TaxOutputType();

            tax.TaxTypeCode = TaxTypeCodeType.Item01;

            object[] tx = { taxRate };
            tax.TaxRate = String.Format(culturaFactura.NumberFormat, "{0:0.00}", tx);

            tax.TaxableBase = new AmountType();

            tax.TaxableBase.TotalAmount = String.Format(culturaFactura.NumberFormat, "{0:0.00}", baseImp);

            if (!moneda.Equals(CurrencyCodeType.EUR))
            {
                tax.TaxableBase.EquivalentInEurosSpecified = true;
                tax.TaxableBase.EquivalentInEuros = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (baseImp * exchangeRate));
            }

            tax.TaxAmount = new AmountType();

            tax.TaxAmount.TotalAmount = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (montoImp));

            if (!moneda.Equals(CurrencyCodeType.EUR))
            {
                tax.TaxAmount.EquivalentInEurosSpecified = true;
                tax.TaxAmount.EquivalentInEuros = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (montoImp * exchangeRate));
            }

            return tax;
        }


        private List<TaxType> getTaxesW(List<TaxType> taxesWithHeld)
        {


            if (calculos.taxesw != null)
            {
                List<Taxes> taxesList = calculos.taxesw.TaxesList;
                if (taxesWithHeld == null)
                    taxesWithHeld = new List<TaxType>();

                foreach (Taxes tax in taxesList)
                {
                    taxesWithHeld.Add(getTaxWithHeld(tax.Taxablebase, double.Parse(tax.TaxType, culturaOffice.NumberFormat), tax.Taxamount));
                }
            }
            return taxesWithHeld;
        }


        /// <summary>
        /// Método utilizado por getTaxesOutputs(), para registrar nuevos tipos de impuestos repercutidos
        /// </summary>
        /// <param name="baseImp">Base imponible sobre la que que se aplicarán los impuestos</param>
        /// <param name="taxRate">Porcentaje de impuesto a aplicar</param>
        /// <param name="montoImp">Importe del impuesto</param>
        /// <returns>Un objeto TaxOutputType que contiene la información del nuevo impuesto</returns>
        private TaxType getTaxWithHeld(double baseImp, double taxRate, double montoImp)
        {
            TaxType tax = new TaxType();

            tax.TaxTypeCode = TaxTypeCodeType.Item04;

            object[] tx = { taxRate };

            tax.TaxRate = String.Format(culturaFactura.NumberFormat, "{0:0.00}", tx);

            tax.TaxableBase = new AmountType();

            tax.TaxableBase.TotalAmount = String.Format(culturaFactura.NumberFormat, "{0:0.00}", baseImp);

            if (!moneda.Equals(CurrencyCodeType.EUR))
            {
                tax.TaxableBase.EquivalentInEurosSpecified = true;
                tax.TaxableBase.EquivalentInEuros = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (baseImp * exchangeRate));
            }

            tax.TaxAmount = new AmountType();

            tax.TaxAmount.TotalAmount = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (montoImp));

            if (!moneda.Equals(CurrencyCodeType.EUR))
            {
                tax.TaxAmount.EquivalentInEurosSpecified = true;
                tax.TaxAmount.EquivalentInEuros = String.Format(culturaFactura.NumberFormat, "{0:0.00}", (montoImp * exchangeRate));
            }

            return tax;
        }

        /// <summary>
        /// Método utilzado para redondeo de los valores, redondea hacia arriba
        /// </summary>
        /// <param name="numero">valor que a redondear</param>
        /// <param name="decimales">número de posisiones decimales a las que se redondeará el número</param>
        /// <returns>el numero redondeado hacia arriba, con los decimales indicados</returns>
        public static double Round3(double numero, int decimales)
        {
            double multi = Math.Pow(10.0d, (double)decimales);

            if (numero < 0)
                return (-(long)((-numero * multi) + 0.5d)) / multi;
            else
                return ((long)((numero * multi) + 0.5d)) / multi;

        }


        /// <summary>
        /// método que se encarga de identificar los indices de las tablas.
        /// <para>
        /// Cada una de las tablas tiene un número en el encabezado, que permite identificarlas sin importar el orden en que aparezcan,
        /// se llama al inicio de cada operacion de cálculos,para aseguraserse de que las las variables de los indices esten actualizadas
        /// en caso de que una tabla haya sido eliminada
        /// 
        /// <example>
        /// se toma el texto del encabezado de la tabla, 
        /// 
        /// <code>string table = this.Tables[i].Rows[1].Cells[1].Range.Text.Trim(x).Trim();</code>
        /// 
        /// con base en el valor de "table", se asigna el indice a cada una de las variables para indices, t1,t2,t3,t4.t5,t6
        /// </example>
        /// </para>
        /// 
        /// </summary>
        private void enumerateTables()
        {
            if (document == null)
                document = Globals.ThisAddIn.Application.ActiveDocument;

            int count = document.Tables.Count;
            if (count <= 0)
            {
                //MessageBox.Show("Esta no es una plantilla valida de facturae");
                ControlMessages msg = ControlMessages.getInstance();
                throw new Exception(msg.getMessage(ControlMessages.Msg.ErrorNotValidTemplate));
            }

            else
            {

                for (int i = 2; i <= document.Tables.Count; i++)
                {
                    try
                    {
                        string table = document.Tables[i].Rows[1].Cells[1].Range.Text.Trim(x).Trim();
                        switch (table)
                        {

                            case "2":
                                t2 = i; break;
                            case "3":
                                t3 = i; break;
                            case "6":
                                t4 = i; break;
                            case "4":
                                t5 = i; break;
                            case "1":
                                t6 = i; break;


                        }
                    }
                    catch (Exception) { }
                }
            }

        }


        #endregion

        #region Public Methods

        /// <summary>
        /// Devuelve el objeto Facturae generado con los datos de la plantilla
        /// </summary>
        /// <returns>Devuelve el objeto Facturae generado con los datos de la plantilla</returns>
        public Facturae getFacturae()
        {
            return facturae;
        }


        /// <summary>
        /// devuelve el valor de un enumerado de tipo xmlEnum
        /// </summary>
        /// <param name="e"> enumerado del cual se desea recuperar el valor</param>
        /// <returns>el valor correspondiente al enumerado, 
        /// <para>
        /// 
        /// <example>
        /// se tiene el siguiente enumerado:
        /// 
        /// <code>
        ///  [XmlTypeAttribute]
        /// public enum elementos
        /// {
        /// ["elemento 1"]
        /// item1,
        /// ["eliminado 2"]
        /// item2
        /// }
        /// </code>
        /// 
        /// la llamada:
        /// <code>
        /// ConvertToString(elementos.item1);
        /// </code>
        /// devuelve: 
        /// 
        /// "elemento 1"
        /// </example>
        /// </para> 
        /// </returns>
        public static string ConvertToString(Enum e)
        {
            // Get the Type of the enum
            Type t = e.GetType();

            // Get the FieldInfo for the member field with the enums name
            FieldInfo info = t.GetField(e.ToString("G"));

            // Check to see if the XmlEnumAttribute is defined on this field
            if (!info.IsDefined(typeof(XmlEnumAttribute), false))
            {
                // If no XmlEnumAttribute then return the string version of the enum.
                return e.ToString("G");
            }

            // Get the XmlEnumAttribute
            object[] o = info.GetCustomAttributes(typeof(XmlEnumAttribute), false);
            XmlEnumAttribute att = (XmlEnumAttribute)o[0];
            return att.Name;
        }

        #endregion

        #region Parser

        /// <summary>
        /// Se encarga de convertir el texto introducido en un DropDownListContentControl en un elemento del enumerado InvoiceIssuerTypeType
        /// </summary>
        /// <param name="tag">texto a convertir en enumerado</param>
        /// <returns>el enumerado correspondiente a tag</returns>
        private InvoiceIssuerTypeType convertToInvoiceIssuerType(string tag)
        {
            if (string.IsNullOrEmpty(tag))
                return InvoiceIssuerTypeType.EM;
            return (InvoiceIssuerTypeType)Enum.Parse(typeof(InvoiceIssuerTypeType), tag);
        }

        /// <summary>
        /// Se encarga de convertir el texto introducido en un DropDownListContentControl en un elemento del enumerado PersonTypeCodeType
        /// </summary>
        /// <param name="tag">texto a convertir en enumerado</param>
        /// <returns>el enumerado correspondiente a tag</returns>
        private PersonTypeCodeType convertToPersonType(string tag)
        {
            if (string.IsNullOrEmpty(tag))
                return PersonTypeCodeType.F;
            return (PersonTypeCodeType)Enum.Parse(typeof(PersonTypeCodeType), tag);
        }

        /// <summary>
        /// Se encarga de convertir el texto introducido en un DropDownListContentControl en un elemento del enumerado PersonTypeCodeType
        /// </summary>
        /// <param name="tag">texto a convertir en enumerado</param>
        /// <returns>el enumerado correspondiente a tag</returns>
        private ResidenceTypeCodeType convertToResidenceType(string tag)
        {
            if (string.IsNullOrEmpty(tag))
                return ResidenceTypeCodeType.U;
            return (ResidenceTypeCodeType)Enum.Parse(typeof(ResidenceTypeCodeType), tag);
        }

        /// <summary>
        /// Se encarga de convertir el texto introducido en un DropDownListContentControl en un elemento del enumerado PersonTypeCodeType
        /// </summary>
        /// <param name="tag">texto a convertir en enumerado</param>
        /// <returns>el enumerado correspondiente a tag</returns>
        private CountryType convertToCountryType(string tag)
        {
            if (string.IsNullOrEmpty(tag))
                return CountryType.ESP;
            return (CountryType)Enum.Parse(typeof(CountryType), tag);
        }

        /// <summary>
        /// Se encarga de convertir el texto introducido en un DropDownListContentControl en un elemento del enumerado PersonTypeCodeType
        /// </summary>
        /// <param name="tag">texto a convertir en enumerado</param>
        /// <returns>el enumerado correspondiente a tag</returns>
        private CurrencyCodeType convertToCurrencyType(string tag)
        {
            if (string.IsNullOrEmpty(tag))
                return CurrencyCodeType.EUR;
            return (CurrencyCodeType)Enum.Parse(typeof(CurrencyCodeType), tag);
        }

        /// <summary>
        /// Se encarga de convertir el texto introducido en un DropDownListContentControl en un elemento del enumerado PersonTypeCodeType
        /// </summary>
        /// <param name="tag">texto a convertir en enumerado</param>
        /// <returns>el enumerado correspondiente a tag</returns>
        private InvoiceDocumentTypeType convertToInvoiceDocumentType(string tag)
        {
            if (string.IsNullOrEmpty(tag))
                return InvoiceDocumentTypeType.FC;
            return (InvoiceDocumentTypeType)Enum.Parse(typeof(InvoiceDocumentTypeType), tag);
        }

        /// <summary>
        /// Se encarga de convertir el texto introducido en un DropDownListContentControl en un elemento del enumerado PersonTypeCodeType
        /// </summary>
        /// <param name="tag">texto a convertir en enumerado</param>
        /// <returns>el enumerado correspondiente a tag</returns>
        private InvoiceClassType convertToInvoiceClassType(string tag)
        {
            if (string.IsNullOrEmpty(tag))
                return InvoiceClassType.CC;
            return (InvoiceClassType)Enum.Parse(typeof(InvoiceClassType), tag);
        }

        /// <summary>
        /// Se encarga de convertir el texto introducido en un DropDownListContentControl en un elemento del enumerado ReasonCodeType
        /// </summary>
        /// <param name="tag">texto a convertir en enumerado</param>
        /// <returns>el enumerado correspondiente a tag</returns>
        private ReasonCodeType convertToReasonCodeType(string tag)
        {
            if (string.IsNullOrEmpty(tag))
                return ReasonCodeType.Item01;
            return (ReasonCodeType)Enum.Parse(typeof(ReasonCodeType), tag);
        }

        /// <summary>
        /// Se encarga de convertir el texto introducido en un DropDownListContentControl en un elemento del enumerado ReasonDescriptionType
        /// </summary>
        /// <param name="tag">texto a convertir en enumerado</param>
        /// <returns>el enumerado correspondiente a tag</returns>
        private ReasonDescriptionType convertToReasonDescriptionType(string tag)
        {
            if (string.IsNullOrEmpty(tag))
                return ReasonDescriptionType.Baseimponible;
            return (ReasonDescriptionType)Enum.Parse(typeof(ReasonDescriptionType), tag);
        }

        /// <summary>
        /// Se encarga de convertir el texto introducido en un DropDownListContentControl en un elemento del enumerado CorrectionMethodType
        /// </summary>
        /// <param name="tag">texto a convertir en enumerado</param>
        /// <returns>el enumerado correspondiente a tag</returns>
        private CorrectionMethodType convertToCorrectionMethodType(string tag)
        {

            if (string.IsNullOrEmpty(tag))
                return CorrectionMethodType.Item01;
            return (CorrectionMethodType)Enum.Parse(typeof(CorrectionMethodType), tag);
        }

        /// <summary>
        /// Se encarga de convertir el texto introducido en un DropDownListContentControl en un elemento del enumerado CorrectionMethodDescriptionType
        /// </summary>
        /// <param name="tag">texto a convertir en enumerado</param>
        /// <returns>el enumerado correspondiente a tag</returns>
        private CorrectionMethodDescriptionType convertToCorrectionMethodDescriptionType(string tag)
        {
            if (string.IsNullOrEmpty(tag))
                return CorrectionMethodDescriptionType.AutorizadasporlaAgenciaTributaria;
            return (CorrectionMethodDescriptionType)Enum.Parse(typeof(CorrectionMethodDescriptionType), tag);
        }

        /// <summary>
        /// Se encarga de convertir el texto introducido en un DropDownListContentControl en un elemento del enumerado TaxTypeCodeType
        /// </summary>
        /// <param name="tag">texto a convertir en enumerado</param>
        /// <returns>el enumerado correspondiente a tag</returns>
        private TaxTypeCodeType convertToTaxTypeCodeType(string tag)
        {
            if (string.IsNullOrEmpty(tag))
                return TaxTypeCodeType.Item01;
            return (TaxTypeCodeType)Enum.Parse(typeof(TaxTypeCodeType), tag);
        }

        /// <summary>
        /// Se encarga de convertir el texto introducido en un DropDownListContentControl en un elemento del enumerado UnitOfMeasureType
        /// </summary>
        /// <param name="tag">texto a convertir en enumerado</param>
        /// <returns>el enumerado correspondiente a tag</returns>
        private UnitOfMeasureType convertToUnitOfMeasureType(string tag)
        {
            if (string.IsNullOrEmpty(tag))
                return UnitOfMeasureType.Item01;
            return (UnitOfMeasureType)Enum.Parse(typeof(UnitOfMeasureType), tag);
        }

        /// <summary>
        /// Se encarga de convertir el texto introducido en un DropDownListContentControl en un elemento del enumerado LanguageCodeType
        /// </summary>
        /// <param name="tag">texto a convertir en enumerado</param>
        /// <returns>el enumerado correspondiente a tag</returns>
        private LanguageCodeType convertToLanguageCodeType(string tag)
        {
            if (string.IsNullOrEmpty(tag))
                return LanguageCodeType.es;
            return (LanguageCodeType)Enum.Parse(typeof(LanguageCodeType), tag);
        }

        /// <summary>
        /// Se encarga de convertir el texto introducido en un DropDownListContentControl en un elemento del enumerado PaymentMeansType
        /// </summary>
        /// <param name="tag">texto a convertir en enumerado</param>
        /// <returns>el enumerado correspondiente a tag</returns>
        private PaymentMeansType convertToPaymentMeansType(string tag)
        {
            if (string.IsNullOrEmpty(tag))
                return PaymentMeansType.Item01;
            return (PaymentMeansType)Enum.Parse(typeof(PaymentMeansType), tag);
        }


        /// <summary>
        /// Define los posibles llamadores para los método que requieren identificar quien los llama
        /// </summary>
        private enum Parent
        {
            ThirdParty,
            SellerParty,
            BuyerParty,
            BatchTIA,
            BatchTOA,
            BatchTEA,
            TaxableBase,
            TaxAmount,
            ItemTB,
            ItemTA

        }


        #endregion

    }
}
